package t2.server;

import java.lang.reflect.InvocationTargetException;

import t2.client.rpc.LocalATcmd;
import t2.server.xbee.XBeeData;
import t2.server.xbee.XBeeNetwork;
import t2.server.xbee.XBeePort;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.rapplogic.xbee.api.ApiId;
import com.rapplogic.xbee.api.AtCommand;
import com.rapplogic.xbee.api.AtCommandResponse;
import com.rapplogic.xbee.api.PacketListener;
import com.rapplogic.xbee.api.XBee;
import com.rapplogic.xbee.api.XBeeException;
import com.rapplogic.xbee.api.XBeeResponse;
import com.rapplogic.xbee.api.zigbee.NodeDiscover;
import com.rapplogic.xbee.util.ByteUtils;

public class LocalATcmdImpl extends RemoteServiceServlet implements LocalATcmd {


    private static final long serialVersionUID = -235767033035989954L;

    /* Use this container for organizing the AT calls and the way their
    returned data
    * should be handled.
    * Example: the value returned from an 'NI' command will be an integer
    array, and to
    * make it readable, it must be processed by the 'toString' method in
    * ByteUtils.
    * For a second example, the value returned from a 'PL' command will be an
    * integer array, but it must be processed by 'convertMultiByteToInt'
    method
    * of ByteUtils to be readable.
    * These associations are stored in the singleton class 'ATcmdMap', and
    * are referenced here. */

    @SuppressWarnings({ "rawtypes" })
    @Override
    public String atcmd(String string) {
        final XBeeNetwork network = XBeeNetwork.getNetwork();
        String s = "error";


        try {
            /* Use the following class and object for processing the return value. */
            Class byteUtilsClass = Class.forName("com.rapplogic.xbee.util.ByteUtils");
            Object byteUtilsObj = byteUtilsClass.newInstance();

            /* Send the input command to the xbee, and capture the response. */
            XBee xbee = XBeePort.getXBeePort().getXbee();


            /* Node Discover is a special case and requires extra processing. */
            if (string.contentEquals("ND")) {

                PacketListener ND = new PacketListener() {

                    @Override
                    public void processResponse(XBeeResponse response) {
                        if (response.getApiId() == ApiId.AT_RESPONSE) {

                            NodeDiscover nd = NodeDiscover.parse((AtCommandResponse) response);

                            /* Create an XBeeData container to hold the data. */
                            // XBeeData xbd = new XBeeData();
                            //
                            // xbd.setAddr(nd.getNodeAddress64());
                            // xbd.setNodeId(nd.getNodeIdentifier());
                            network.add(new XBeeData(nd.getNodeAddress64(), nd.getNodeIdentifier(), nd.getDeviceType()
                                    .getValue()));

                            if (nd.getDeviceType() == NodeDiscover.DeviceType.DEV_TYPE_COORDINATOR) {
                                XBeeNetwork.setHasCoordinator(true);
                            }
                        }
                    }
                };

                xbee.addPacketListener(ND);
                xbee.sendAsynchronous(new AtCommand(string));
                Thread.sleep(6000);
                xbee.clearResponseQueue();
                xbee.removePacketListener(ND);


            } else {
                xbee.sendAsynchronous(new AtCommand(string));
                AtCommandResponse response = (AtCommandResponse) xbee.getResponse();

                /* Send the response to the method stored in the map for the input
                command. */
                Object returnedString = ATcmdMap.getInstance().getMap().get(string)
                        .invoke(byteUtilsObj, response.getValue());
                return returnedString.toString();
            }
        }
        catch (SecurityException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        catch (InstantiationException e) {
            e.printStackTrace();
        }
        catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        catch (XBeeException e) {
            e.printStackTrace();
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        return s;
    }

    @Override
    public String atcmd(String string, int param) {
        String s = "error";

        try {
            @SuppressWarnings("rawtypes")
            Class byteUtilsClass = Class.forName("com.rapplogic.xbee.util.ByteUtils");
            Object byteUtilsObj = byteUtilsClass.newInstance();

            /* Send the input command to the xbee, and capture the response. */
            XBee xbee = XBeePort.getXBeePort().getXbee();
            xbee.sendAsynchronous(new AtCommand(string, param));
            AtCommandResponse response = (AtCommandResponse) xbee.getResponse();


            /* Send the response to the method stored in the map for the input
            command. */
            Object returnedString = ATcmdMap.getInstance().getMap().get(string)
                    .invoke(byteUtilsObj, response.getValue());
            return returnedString.toString();
        }
        catch (SecurityException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        catch (InstantiationException e) {
            e.printStackTrace();
        }
        catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        catch (XBeeException e) {
            e.printStackTrace();
        }
        return s;
    }


    @Override
    public String atcmd(String string, String param) {
        String s = "error";

        try {
            @SuppressWarnings("rawtypes")
            Class byteUtilsClass = Class.forName("com.rapplogic.xbee.util.ByteUtils");
            Object byteUtilsObj = byteUtilsClass.newInstance();

            /* Send the input command to the xbee, and capture the response. */
            XBee xbee = XBeePort.getXBeePort().getXbee();

            xbee.sendAsynchronous(new AtCommand(string, ByteUtils.stringToIntArray(param)));
            AtCommandResponse response = (AtCommandResponse) xbee.getResponse();


            /* Send the response to the method stored in the map for the input
            command. */
            Object returnedString = ATcmdMap.getInstance().getMap().get(string)
                    .invoke(byteUtilsObj, response.getValue());
            return returnedString.toString();
        }
        catch (SecurityException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        catch (InstantiationException e) {
            e.printStackTrace();
        }
        catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        catch (XBeeException e) {
            e.printStackTrace();
        }
        return s;
    }
}
